/* LIBDGL -- a Directed Graph Library implementation
 * Copyright (C) 2002 Roberto Micarelli
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

/* best view tabstop=4
 */

/*@*********************************************************************
 * @pack:	GNO_PACK
 * @descr:	Command line options utility.
 *
 * @notes:	Support to easily parse command line options. Some concepts
 *			were taken from the posix getopt() family functions, while
 *			our specific experience in C programming suggested us a
 *			proprietary implementation to make source code more readable
 *			at life easier (I hope).
 *			Option format:
 *
 *			syntax				name
 *			----------------------------------------------
 *			--option=value		long-parametric
 *			--option			long-boolean
 *			-option value		short-parametric
 *			-option				short-boolean
 *
 *		C sample:
 *		----------------------------------------------
 *		#include <stdio.h>
 *		#include <opt.h>
 *
 *		int main( int argc , char ** argv )
 *		{
 *			Boolean		fHelp;
 *			Boolean		fTcp;
 *			Boolean		fUdp;
 *			char	*	pszProtocol;
 *			char	*	pszInterface;
 *			int			i;
 *
 *			GNO_BEGIN
 *			GNO_SWITCH( "h", "help", False , & fHelp , "Print this help." )
 *			GNO_SWITCH( "t", "tcp", False , & fTcp , NULL )
 *			GNO_SWITCH( "u", "udp", False , & fUdp , NULL )
 *			GNO_OPTION( "p", "protocol", "tcp" , & pszProtocol , NULL )
 *			GNO_OPTION( "i", "interface", "eth0" , & pszInterface , NULL )
 *			GNO_END
 *
 *
 *			if ( GNO_PARSE( argc , argv ) < 0 )
 *			{
 *				return 1;
 *			}
 *
 *			if ( fHelp == True )
 *			{
 *				GNO_HELP( "t_opt usage" );
 *				return 0;
 *			}
 *
 *			printf ( "t/tcp  = %s\n", (fTcp  == True) ? "True" : "False" );
 *			printf ( "u/udp  = %s\n", (fUdp  == True) ? "True" : "False" );
 *			printf ( "p/protocol  = <%s>\n", pszProtocol );
 *			printf ( "i/interface = <%s>\n", pszInterface );
 *
 *			GNO_FREE();
 *
 *			printf( "orphan options:\n" );
 *
 *			for ( i = 0 ; i < argc ; i ++ )
 *			{
 *				if ( argv[ i ] )
 *				{
 *					printf( "arg %d: %s\n", i, argv[i ] );
 *				}
 *				else
 *				{
 *					printf( "arg %d: --\n", i );
 *				}
 *			}
 *			return 0;
 *		}
 *						
 **********************************************************************/

#ifndef _GNOPT_H_
#define _GNOPT_H_

#ifdef __cplusplus
extern "C" {
#endif

/***********************************************************************
 *				DEFINES
 **********************************************************************/
/*@*--------------------------------------------------------------------
 * @defs:	GNO_FLG
 * @descr:	flags used to set the nFlg field in the GnoOption_s
 *			SWITCH    = boolean option required
 *
 * @see:	GnoOption_s
 *
 *--------------------------------------------------------------------*/

#define GNO_FLG_SWITCH		0x01

/*@*--------------------------------------------------------------------
 * @defs:	True/False
 * @descr:	one more useful (?) true/false definition
 *
 *--------------------------------------------------------------------*/
#define True  1
#define False 0

/***********************************************************************
 *				STRUCTS/UNIONS/TYPES/FUNCDEFS
 **********************************************************************/
/*@*--------------------------------------------------------------------
 * @type:	Boolean
 * @descr:	wasn't it better to use 'int'?
 *--------------------------------------------------------------------*/
typedef int Boolean;

/*@*--------------------------------------------------------------------
 * @type:	GnoOption_s
 * @descr:	This structure describes an option. We intend to use an array
 *          of GnoOption_s, terminated by a 'NULL' entry (one containing
 *			all binary-zero fields), and to pass it to GnoParse() together
 *			with the typical argc,argv couple of main() args. The array's
 *			entries are looked-up and filled with coherent argc,argv
 *			values. Some fields are statically filled by user while other
 *			are returned by the GnoParse() function.
 *			Fields set by the user:
 *
 *			nFlg      = So far the only supported flag is GNO_FLG_SWITCH
 *			            to address a boolean option type.
 *			fDef      = The default value for a boolean option.
 *			pszDef    = The default value for a parametric option.
 *			pszShort  = The short name of the option.
 *			pszLong   = The long name of the option.
 *			pfValue   = Pointer to a boolean option return value.
 *			ppszValue = Pointer to a parametric option return value.
 *			pszDescr  = A brief option description
 *
 *			Fields set by GnoParse():
 *
 *			iArg	   = argv option index
 *			*ppszValue = pointer to parametric option value 
 *			*pfValue   = True/False
 *
 *			User supplied fields are mandatory only within specific
 *			conditions:
 *
 *			- at least one of pszShort/pszLong must be specified
 *			- fDef and pfValue apply to a boolean option only
 *			- pszDef and ppszValue apply to a parametric option only
 *			- pszDescr is optional
 *
 * @see:	GnoParse(), GNO_FLG
 *
 *--------------------------------------------------------------------*/

typedef struct GnoOption
{
	int			iArg;		/* returned argv option index */
	int			nFlg;		/* flags describing the option */
	Boolean 	fDef;		/* default returned value for a boolean option */
	char *		pszDef;		/* default returned value for a parametric option */
	char *		pszShort;	/* short-option recogniser */
	char *		pszLong;	/* long-option recogniser */
	Boolean *	pfValue;	/* address to return a boolean option */
	char **		ppszValue;	/* address to return a parametric option */
	char *		pszDescr;	/* a brief option description */

} GnoOption_s;


/***********************************************************************
 *				MACROS
 **********************************************************************/
/*@*--------------------------------------------------------------------
 *
 * @macro:	GNO_BEGIN
 * @descr:	Begin an option array declaration
 * 
 * @notes:	The best use is to start option declaration immediately after
 *			the automatic-variable declaration in the main() function.
 *
 *--------------------------------------------------------------------*/
#define GNO_BEGIN GnoOption_s _aopt[] = {

/*@*--------------------------------------------------------------------
 *
 * @macro:	GNO_OPTION
 * @descr:	Declare a parametric option
 *
 * 
 * @args:	I:	chsopt	=	short option character
 *			I:	pszlopt	->	long option psz
 *			I:	pszdef 	->	default-returned psz
 *			I:	ppszv 	->	user-addressed return variable pointer
 *
 *--------------------------------------------------------------------*/
#define GNO_OPTION(pszsopt,pszlopt,pszdef,ppszv,pszdescr) \
			{ 0, 0, 0, pszdef, pszsopt, pszlopt, NULL, ppszv, pszdescr },

/*@*--------------------------------------------------------------------
 *
 * @macro:	GNO_SWITCH
 * @descr:	Declare a boolean option
 * 
 * @args:	I:	chsopt	=	short option character
 *			I:	pszlopt	->	long option psz
 *			I:	fdef 	=	default-returned Boolean
 *			I:	pfv		->	user-addressed return variable pointer
 *
 *--------------------------------------------------------------------*/
#define GNO_SWITCH(pszsopt,pszlopt,fdef,pfv,pszdescr) \
			{	\
				0, \
				GNO_FLG_SWITCH, \
				fdef, NULL, \
				pszsopt, pszlopt, \
				pfv, NULL, \
				pszdescr \
			},

/*@*--------------------------------------------------------------------
 *
 * @macro:	GNO_PARSE
 * @descr:	Parse a GnoOption_s array declaration
 * 
 * @args:	I:	argc 	=	count of argv entries
 *			I:	argv	->	array of sz pointers
 *
 *--------------------------------------------------------------------*/
#define GNO_PARSE(argc,argv) GnoParse( (argc), (argv), _aopt )

/*@*--------------------------------------------------------------------
 *
 * @macro:	GNO_END
 * @descr:	Terminate an option array declaration
 * 
 *--------------------------------------------------------------------*/
#define GNO_END	{ 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL } };

/*@*--------------------------------------------------------------------
 *
 * @macro:	GNO_HELP
 *
 * @descr:	Print a brief option's help on the standard error
 *
 * @args:	I:	pszhead ->	help header string
 * 
 *--------------------------------------------------------------------*/
#define GNO_HELP(pszhead) GnoHelp( pszhead , _aopt )

/*@*--------------------------------------------------------------------
 *
 * @macro:	GNO_FREE
 *
 * @descr:	Free resources created by a previously parsed array
 *
 * 
 *--------------------------------------------------------------------*/
#define GNO_FREE() GnoFree( _aopt )


/***********************************************************************
 *				FUNCTION PROTOTYPES
 **********************************************************************/

extern int GnoParse( int argc , char ** argv , GnoOption_s * pOpt );

extern void GnoFree( GnoOption_s * pOpt );

extern void GnoHelp( char *pszHead, GnoOption_s * pOpt );


#ifdef __cplusplus
}
#endif

#endif /* top of file */

/***************************** END OF FILE ****************************/
